﻿using MPSizectorDotNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using VisionConfig;

namespace CameraMPSizector
{
    public class MPSizectorCamera
    {

        private MPSizector device;
        private MP3DFrameManaged[] buffer3DCallBack;
        private MP3DFrameManaged currentBuffer3D;
        public static HObject XPicture = new HObject();
        public static HObject YPicture = new HObject();
        public static HObject ZPicture = new HObject();
        public static HObject GrayPicture = new HObject();
        private long totalNum = 0;
        bool flag = false;
        bool first = false;
        uint len;
        float[] X ;
        float[] Y ;
        float[] Z ;
        byte[] Gray ;

        public MPSizector Device=new MPSizector();

        public int InitialCamera(double[] db)
        {


            

            Form1 fm = new Form1();
            fm.Device = Device;
            if (fm.ShowDialog()== DialogResult.OK)
            {
                device = fm.Device;
            }
            else
            {
                return -1;
            }


            /// 接口内置设备选择界面
            /// Built-in dialog for device selection.
            /// 
            //var SelectDialog = new MPSizectorSelectDialog();

            //if (SelectDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            //{
            //    device = SelectDialog.Device;
            //}
            //else
            //{
            //    SelectDialog.Close();
            //    return -1;
            //}

            /// 给设备设定外部触发模式/Setting Trigger Type to the device.
            /// TriggerType: 
            ///             TriggerSourceNoTrigger                 --- 无外部触发模式，只能通过FireSoftwareTrigger方法软触发 / No external trigger. Can only be triggered by FireSoftwareTrigger() method.
            ///             TriggerSourceKeepRunning               --- 设备内部时钟触发，使得设备持续拍摄。    /   Triggered by internal clock. Device scans continously.
            ///             TriggerSourceTriggerSourceExtIX X~0-7  --- 设定外部触发的IO端口。FireSoftwareTrigger()方法任然可用  / Assign external trigger port. FireSoftwareTrigger() is still available.
            //device.TriggerSource = TriggerSourceType.TriggerSourceNoTrigger;
            InitialData(db);
            device.HoldState = false;


            /// 使用Set3DDataCallBack，Set3DDataCallBackUnmanaged函数给设备类指定委托。
            /// 返回值为获得的数据。
            /// Using Set3DDataCallBack, Set3DDataCallBackUnmanaged, etc to assign post process delegate for 
            /// the scanner. The returned value is the acquired data.
            buffer3DCallBack = device.Set3DDataCallBackManaged(ScanCallBack, 1);
            device.FireSoftwareTrigger();
            return 0;

        }
        public int GenPicture()
        {
            /// 直接软触发设备，通过回调函数获得数据
            /// Trigger the device directly. Data is acquired through callback function.
            /// 

            flag = true;
            bool flgf = false;
            for (int i = 0; i < 7; i++)
            {
                flgf= device.FireSoftwareTrigger();
                if (flgf)
                {
                    break;
                }
                Thread.Sleep(5);
            }
            if (!flgf)
            {
                MessageBox.Show("相机断开连接");
            }

            int timelost = 0;
            int adds = 0;
            int fg = 0;
            while (flag)
            {
                if (timelost>150)
                {
                    if (fg>3)
                    {
                        //MessageBox.Show("相机故障获取数据失败");
                        adds = 0;
                        break;
                    }
                    else
                    {
                        timelost = 0;
                        fg++;
                        device.FireSoftwareTrigger();
                    }
                    
                }
                Thread.Sleep(10);
                timelost++;
                adds++;
            }
            return adds;
        }
        private void ScanCallBack(byte BufferIndex)
        {
            /// BufferIndex：缓存数组中最后一帧3D数组的下标
            /// BufferIndex is the index to the last frame in the Buffer
            try
            {
                currentBuffer3D = buffer3DCallBack[BufferIndex];
                if (!first)
                {
                    len = currentBuffer3D.SensorWidth * currentBuffer3D.SensorHeight;
                    X = new float[len];
                    Y = new float[len];
                    Z = new float[len];
                    Gray = new byte[len];
                    first = true;
                }
                currentBuffer3D.PostProcessRemoveBurrs();
                currentBuffer3D.PostProcessMend();
                currentBuffer3D.PostProcessFiltrate();

                ParallelLoopResult result =
                Parallel.For(0, currentBuffer3D.Data.Length, i =>
                {
                    if (float.IsNaN(currentBuffer3D.Data[i].X) | float.IsNaN(currentBuffer3D.Data[i].Y) | float.IsNaN(currentBuffer3D.Data[i].Z) | (currentBuffer3D.Data[i].Mask != 0))
                    {
                        X[i] = 2000;
                        Y[i] = 2000;
                        Z[i] = 2000;
                    }
                    else
                    {
                        X[i] = currentBuffer3D.Data[i].X;
                        Y[i] = currentBuffer3D.Data[i].Y;
                        Z[i] = currentBuffer3D.Data[i].Z;
                    }
                    Gray[i] = currentBuffer3D.Data[i].Gray;
                });
                //XPicture.Dispose();
                //YPicture.Dispose();
                //ZPicture.Dispose();
                //GrayPicture.Dispose();

                int widths = (int)currentBuffer3D.SensorWidth;
                int heights = (int)currentBuffer3D.SensorHeight;

                //XPicture = HObjectConvertFromBitmap((int)currentBuffer3D.SensorHeight, (int)currentBuffer3D.SensorWidth, Dat(X));
                //YPicture = HObjectConvertFromBitmap((int)currentBuffer3D.SensorHeight, (int)currentBuffer3D.SensorWidth, Dat(Y));
                //ZPicture = HObjectConvertFromBitmap((int)currentBuffer3D.SensorHeight, (int)currentBuffer3D.SensorWidth, Dat(Z));
                //GrayPicture = HObjectConvertGray((int)currentBuffer3D.SensorHeight, (int)currentBuffer3D.SensorWidth, Datbyte(Gray));


                HOperatorSet.GenImage1(out XPicture, "real", widths, heights, Dat(X));
                HOperatorSet.GenImage1(out YPicture, "real", widths, heights, Dat(Y));
                HOperatorSet.GenImage1(out ZPicture, "real", widths, heights, Dat(Z));
                HOperatorSet.GenImage1(out GrayPicture, "byte", widths, heights, Datbyte(Gray));


                HObject region, copregion;
                HOperatorSet.Threshold(XPicture, out region, 2000, 2000);
                HOperatorSet.Complement(region, out copregion);
                region.Dispose();
                HOperatorSet.ReduceDomain(XPicture, copregion, out XPicture);
                HOperatorSet.ReduceDomain(YPicture, copregion, out YPicture);
                HOperatorSet.ReduceDomain(ZPicture, copregion, out ZPicture);
                copregion.Dispose();
            }
            catch (Exception)
            {

                MessageBox.Show("相机故障");
            }
            flag = false;
        }
        public void InitialData(double[] db)
        {
            device.TriggerSource = TriggerSourceType.TriggerSourceNoTrigger;
            device.ExposureTime = (ushort)db[0];
            device.LEDCurrent = (byte)db[1];
        }
     



        private unsafe IntPtr Dat(float[] fl)
        {
            void* p;
            IntPtr ptr;
            fixed (float* pc = fl)
            {

                p = (void*)pc;
                ptr = new IntPtr(p);
            }       
            return ptr;
        }
        private unsafe IntPtr Datbyte(byte[] fl)
        {
            void* p;
            IntPtr ptr;
            fixed (byte* pc = fl)
            {

                p = (void*)pc;
                ptr = new IntPtr(p);
            }
            return ptr;
        }
        public static HObject HObjectConvertFromBitmap(int height, int width, IntPtr ip)
        {
            try
            {
                HObject ho_Image;
                HOperatorSet.GenEmptyObj(out ho_Image);
                HOperatorSet.GenImage1(out ho_Image, "real", width, height, ip);
                return ho_Image;
            }
            catch (Exception e)
            {
                MessageBox.Show("相机连接错误");
                return null;
            }
        }
        public static HObject HObjectConvertGray(int height, int width, IntPtr ip)
        {
            try
            {
                HObject ho_Image;
                HOperatorSet.GenEmptyObj(out ho_Image);
                HOperatorSet.GenImage1(out ho_Image, "byte", width, height, ip);
                return ho_Image;
            }
            catch (Exception e)
            {
                MessageBox.Show("相机连接错误");
                return null;
            }
        }

    }
}
